use std::ops::Deref;

use crate::byte::*;
use crate::workspace::WorkSpace;

use super::{JumpTable, LitError};
use super::error::LitResult;

pub struct LiteralStream {
    data:Vec<u8>,
}

impl LiteralStream {
    pub fn serialize_into<W:ByteWrite>(&self, _writer:&mut ByteWriter<W>) -> LitResult<()> {
        todo!()
    }

    pub fn deserialize_from(jump_table:Option<&JumpTable>, raw_data:&[u8], workspace:&WorkSpace) -> LitResult<Self> {
        let mut data = Vec::new();
        match jump_table {
            Some(jump_table) => { Self::decode_streams(jump_table, raw_data, workspace, &mut data)?; },
            None => { Self::decode_stream(raw_data, workspace, &mut data)?; },
        }
        Ok(data.into())
    }

    
    pub fn decode_streams(jump_table:&JumpTable, raw_data:&[u8], workspace:&WorkSpace, literals_stream:&mut Vec<u8>) -> LitResult<()> {
        let ranges = jump_table.stream_offset();
        Self::decode_stream(&raw_data[ranges[0].clone()], workspace, literals_stream)?;
        Self::decode_stream(&raw_data[ranges[1].clone()], workspace, literals_stream)?;
        Self::decode_stream(&raw_data[ranges[2].clone()], workspace, literals_stream)?;
        Self::decode_stream(&raw_data[ranges[3].clone()], workspace, literals_stream)?;
        Ok(())
    }

    pub fn decode_stream(raw_data:&[u8], workspace:&WorkSpace, literals_stream:&mut Vec<u8>) -> LitResult<()> {
        let mut reverse_raw_data = raw_data.to_vec();
        reverse_raw_data.reverse();

        let mut byte_reader = ByteReader::new(std::io::Cursor::new(reverse_raw_data));
        let mut bit_reader = BitReader::new(&mut byte_reader);
        bit_reader.read_reverse_padding()?;

        let huffman_table = workspace.huffman_table.as_ref().ok_or(LitError::HuffmanTableMissing)?;
        let root = huffman_table.root();
        let mut huffman_state = root;

        while bit_reader.bits_num() != raw_data.len() * 8 {
            let bit = bit_reader.read_reverse_bits::<u8>(1)?;
            huffman_state = huffman_state.next(bit);
            if let Some(literal) = huffman_state.literal() {
                literals_stream.push(literal);
                huffman_state = root;
            }
        } 

        Ok(())
    }
}

impl From<Vec<u8>> for LiteralStream {
    fn from(data: Vec<u8>) -> Self {
        Self { data }
    }
}
impl std::fmt::Debug for LiteralStream {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let data_string = String::from_utf8(self.data.clone());
        match data_string {
            Ok(data_string) => f.debug_tuple("StringStream").field(&data_string).finish(),
            Err(_) => f.debug_tuple("RawStream").field(&self.data).finish(),
        }
    }
}

impl Deref for LiteralStream {
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}